package de.mnit.schnipsel.db;

import de.mnit.basis.crypt.JavaBase64;
import de.mnit.basis.crypt.cipher.JAVA_CIPHER;
import de.mnit.basis.crypt.cipher.JavaCipher;
import de.mnit.basis.crypt.digest.JAVA_DIGEST;
import de.mnit.basis.crypt.digest.JavaDigest;
import de.mnit.basis.daten.FormatText;
import de.mnit.basis.daten.Zufall;
import de.mnit.basis.db.konstant.DBMS;
import de.mnit.basis.db.sys3e.e1_basis.A_E1_H;
import de.mnit.basis.fehler.Fehler;
import de.mnit.basis.fehler.system.F_Sys_Sicherheit;
import de.mnit.basis.swt.dialog.SWT_Dialog;
import de.mnit.basis.swt.dialog.SWT_Fehler;
import de.mnit.basis.sys.Ausgabe;
import de.mnit.schnipsel.zentral.SC_Crypt;

/**
 * @author Michael Nitsche
 */
public class DBZ_Konfig extends A_E1_H<DBManager> {

	private final B_Konfig k=B_Konfig.info;
	public enum SCHLUESSEL {
		CRYPTLEVEL,
		PASSHASH,
		PASSDB,
		SYNCZEIT
	};


	public DBZ_Konfig(DBManager manager) {
		super(manager, "konfig");
//		db().befehl("ALTER TABLE "+tab+" DROP COLUMN geschuetzt");
	}


	// GLOBAL

	public String gib(SCHLUESSEL schluessel, String standard) {
		String sql="SELECT "+k.WERT.gName()+" FROM "+tab+" WHERE "+k.SCHLUESSEL.gName()+"="+FormatText.zuDB_Text(schluessel.name().toLowerCase());
		String erg=this.db().gibString(sql);
		return erg==null ? standard : erg;
	}

	public void setze(SCHLUESSEL schluessel, String wert) {
		String aktuell=gib(schluessel, null);
		String ts=FormatText.zuDB_Text(schluessel.name().toLowerCase());
		String tw=FormatText.zuDB_Text(wert);
		String sql= aktuell==null
			? "INSERT INTO "+tab+" ("+k.SCHLUESSEL.gName()+","+k.WERT.gName()+")"+" VALUES ("+ts+","+tw+")"
			: "UPDATE "+tab+" SET "+k.WERT.gName()+"="+tw+" WHERE "+k.SCHLUESSEL.gName()+"="+ts;
		this.db().befehl(sql);
	}

	// DETAIL

	public CRYPTLEVEL gCryptLevel() {
		String cryptlvl=DBManager.konfig().gib(DBZ_Konfig.SCHLUESSEL.CRYPTLEVEL, ""+CRYPTLEVEL.OFFEN.ordinal());
		return cryptlvl.equals(""+CRYPTLEVEL.OFFEN.ordinal()) ? CRYPTLEVEL.OFFEN : CRYPTLEVEL.INHALT;
	}

	public void sCryptLevel(CRYPTLEVEL c) {
		DBManager.konfig().setze(DBZ_Konfig.SCHLUESSEL.CRYPTLEVEL, ""+c.ordinal());
	}

	public boolean passAngelegt() {
		return this.gib(SCHLUESSEL.PASSHASH, null)!=null;
	}

	public boolean pruefeUserPass(byte[] pass) {
		if(!this.passAngelegt())
			Fehler.sonstige.da_Verboten();
		byte[] hashdb=JavaBase64.entschluesseln(this.gib(SCHLUESSEL.PASSHASH, ""));
		Ausgabe.debug(pass, hashdb.length, hashdb);
		if(pass.length==0 && hashdb.length==0)
			Fehler.sonstige.da_Verboten();

		JavaDigest hashAlgo=JavaDigest.neu(JAVA_DIGEST.SHA512);
		hashAlgo.plus(pass);
		byte[] hashcalc=hashAlgo.berechnen();
		Ausgabe.debug(hashdb, hashcalc);
		if(hashdb.length!=hashcalc.length)
			return false;
		for(int i=0; i<hashdb.length; i++)
			if(hashdb[i] != hashcalc[i])
				return false;
		return true;
	}

	/** Anlegen oder ändern */
	public void passSetzen(byte[] passNeu) {
		Fehler.zahl.wenn_ZuKlein(1, passNeu.length);
		Ausgabe.debug(passNeu);
		passNeu=SC_Crypt.pass16(passNeu);
		Ausgabe.debug(passNeu);

		boolean angelegt= this.passAngelegt();

		byte[] dbPass=angelegt
			? SC_Crypt.i().gDBPass()
			: Zufall.bytes(JAVA_CIPHER.AES.laengeMax); //Neuen DB-Pass erstellen
		if(dbPass==null) {
			SWT_Dialog.warnung("Passwort konnte nicht geändert werden!");
			return;
		}

		JavaCipher cryptAlgo=new JavaCipher(JAVA_CIPHER.AES);
		try {
			JavaDigest hashAlgo=JavaDigest.neu(JAVA_DIGEST.SHA512);
			hashAlgo.plus(passNeu);
			this.setze(SCHLUESSEL.PASSHASH, JavaBase64.verschluesseln(hashAlgo.berechnen()));
			this.setze(SCHLUESSEL.PASSDB, JavaBase64.verschluesseln(cryptAlgo.verschluesseln(dbPass, passNeu)));
		}
		catch(F_Sys_Sicherheit e) {
			SWT_Fehler.zeig(e, true);
		}
	}

	public byte[] gibDBPass(byte[] userpass) {
		boolean angelegt= this.passAngelegt();
		if(!angelegt)
			throw SWT_Fehler.neu("Passwort noch nicht angelegt!", true);

		try {
			JavaCipher cryptAlgo=new JavaCipher(JAVA_CIPHER.AES);
			return cryptAlgo.entschluesseln(JavaBase64.entschluesseln(this.gib(SCHLUESSEL.PASSDB, "")), userpass);
		}
		catch(F_Sys_Sicherheit e) {
			throw SWT_Fehler.zeig(e, true);
		}
	}

	// INTERN

	protected void erstellen() {
		DBMS dbms=this.m().gDBMS();
		if(dbms==DBMS.HSQLDB) {
//			NeuTab_HSqlDB tab=new NeuTab_HSqlDB(this.m().direkt(), this.tab);
//			tab.spaltenErstellen(B_Konfig.info);
			this.b("CREATE TABLE konfig(" +
				"id INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 0) NOT NULL PRIMARY KEY," +
				"schluessel VARCHAR(256) NOT NULL," +
				"wert VARCHAR(256))");
			this.b("CREATE INDEX i_schluessel ON konfig (schluessel)");
		}
		else if(dbms==DBMS.MYSQL) {
			this.b("CREATE TABLE konfig(" +
				"id INTEGER NOT NULL AUTO_INCREMENT," +
				"schluessel VARCHAR(256) NOT NULL," +
				"wert VARCHAR(256)," +
				"PRIMARY KEY(id))");
			this.b("CREATE INDEX i_schluessel ON konfig (schluessel)");
		}
		else Fehler.sonstige.da_ToDo(dbms);
//		this.b("ALTER TABLE "+this.tab+" ALTER COLUMN "+B_Konfig.info.ID.gName()+" RESTART WITH 100;");
	}

}
